//=======================================================
//AUTHOR: JEFF XL. ZHANG ARIZONA STATE UNIVERSITY
//ALL RIGHTS RESERVED  2008
//=======================================================
#pragma once
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <math.h>
#include <vector>
#include <stdio.h>
#include <iostream>
#define CV_GOLDEN_RATIO 0.618

class Histogram{

public:
	//DIMENSION 3 - GRAYLEVEL 0-255
	//DIMENSION 2 - CHANNELS 0_2+3_5 - RGBHSV
	//DIMENSION 1 - SIDENESS 0_2 - LEFT(1) RIGHT(2) ALL(3)
	int value_hsv[3][3][256];		
	int value_rgb[3][3][256];
//	int value_hsv[_dim1][_dim2][_dim3];		
//	int value_rgb[_dim1][_dim2][_dim3];
	Histogram(int d1 = 3, int d2 = 3, int d3 = 256);
	void visualize(int scalar_visual_1, int scalar_visual_2, int index_frame);
	int max[3][3];		//Max(w) FOR LATER HISTOGRAM VERTICAL SCALING 
	int get_dimension1(void) const;
	int get_dimension2(void) const;
	int get_dimension3(void) const;
private:
	int _dim1;
	int _dim2;
	int _dim3;
	void increment(IplImage* img,const int &bin,const int &level, const int &scalar_visual_1, const int &scalar_visual_2);

friend class LineFeatureDetector;		
friend class FeatureComparison;		
};

Histogram::Histogram(int d1, int d2, int d3){
	//DIMENSION 1 - GRAYLEVEL 0-255
	//DIMENSION 2 - CHANNELS 0-5 - RGBHSV
	//DIMENSION 1 - SIDENESS 0-2 - LEFT(1) RIGHT(2) ALL(3)
	_dim1 = d1;
	_dim2 = d2;
	_dim3 = d3;

	for(int i = 0; i < _dim1; i++){		//3
		for(int j = 0; j < _dim2; j++){		//3
			max[i][j] = 0;
			for(int k = 0; k < _dim3; k++){			//255
				value_hsv[i][j][k] = .0;
				value_rgb[i][j][k] = .0;
			}
		}
	}
}

int Histogram::get_dimension1() const{	return _dim1; }	
int Histogram::get_dimension2() const{	return _dim2; }	
int Histogram::get_dimension3() const{	return _dim3; }	



void Histogram::visualize(int scalar_visual_1, int scalar_visual_2, int index_frame){
	int hist_height = 1000;
//	IplImage *hist_visualization_static = cvCreateImage(cvSize(scalar_visual_1*_dim3,scalar_visual_2*hist_height),8,1);		//STATIC ARBITRARY VALUE 300 CHOSEN BY HAND
	int i = 2; //FOR BOTH SIDES 
	int normalizer_hsv[3] = {0,0,0};
	int normalizer_rgb[3] = {0,0,0};
	int max_hsv = 0;
	int max_rgb = 0;
	//INITIALIZE THE VALUE
	for(int j = 0; j < _dim2; j++){		// FOR ALL 3 CHANNELS
		for(int k = 0; k < _dim3; k++){		// FOR ALL 255 VALUES
			normalizer_hsv[j] += value_hsv[i][j][k];
			normalizer_rgb[j] += value_rgb[i][j][k];
			max_hsv = (max_hsv > value_hsv[i][j][k])?max_hsv:value_hsv[i][j][k];
			max_rgb = (max_rgb > value_rgb[i][j][k])?max_rgb:value_rgb[i][j][k];
		}
	}
	
	IplImage *hist_visualization = cvCreateImage(cvSize(scalar_visual_1*_dim3,scalar_visual_2*CV_GOLDEN_RATIO*_dim3),8,1);		//STATIC ARBITRARY VALUE 300 CHOSEN BY HAND
	char hist_win_name[100];
	int j_mirror = 0;
	for(int j = 0; j < _dim2; j++){		// FOR ALL 3 CHANNELS
		cvZero(hist_visualization);
		for(int k = 0; k < _dim3; k++){		// FOR ALL 255 VALUES
			increment(hist_visualization,k,value_rgb[i][j][k]*CV_GOLDEN_RATIO*_dim3/max_rgb,scalar_visual_1,scalar_visual_2);
		}
		sprintf(hist_win_name,"hist_channel_%d",j);
//		sprintf(hist_win_name,"line_%d_hist_channel_%d",index_frame,j);		//FOR DEBUGGING, LINE-WISE
		Display(hist_win_name,hist_visualization);
		j_mirror++;
	}
	//VISUALIZE HISTOGRAM LINE BY LINE
/*	cvWaitKey(0);
	for(int j = 0; j < _dim2; j++){		// FOR ALL 3 CHANNELS
		sprintf(hist_win_name,"line_%d_hist_channel_%d",index_frame,j);
		cvDestroyWindow(hist_win_name);
	}
*/
//	Display("hist",hist_visualization_static);
}
//DRAW PIXELS ON ASSIGNED LOCATION OF HISTOGRAM
void Histogram::increment(IplImage* img,const int &bin,const int &level, const int &scalar_visual_1, const int &scalar_visual_2){
	for(int y = 0; y < level; y++){
		for(int r_y = 0; r_y < scalar_visual_2; r_y++){
			for(int r_x = 0; r_x < scalar_visual_1; r_x++){
//				img->imageData[img->widthStep*(y+r_y) + bin + r_x] = 255;		//ORIGINAL
				img->imageData[img->widthStep*(img->height-1-(y+r_y)) + bin + r_x] = 255;		//REVERSED VERTICALLY
			}
		}
	}
}


class Ladder{
public:
	int stair;
	Ladder();
	void increase();
	void decrease();
	void reset();
};

Ladder::Ladder(){
	stair = 0;
}

void Ladder::increase(){
	stair++;
}

void Ladder::decrease(){
	stair--;
}

void Ladder::reset(){
	stair = 0;
}




class IndexPair{
public:
	IndexPair();
	void set_index(int index1,int index2);
	int get_index1() const;
	int get_index2() const;
	void print() const;
private:
	int _index1;
	int _index2;
};

IndexPair::IndexPair(){
}

void IndexPair::set_index(int index1, int index2){
	_index1 = index1;
	_index2 = index2;
}

int IndexPair::get_index1()const{
	return _index1;
}

int IndexPair::get_index2()const{
	return _index2;
}

void IndexPair::print() const{
	cout<<"("<<_index1<<","<<_index2<<")"<<endl;
}